package titt.io.socket.in;

import java.io.IOException;
import java.io.InputStream;

import titt.util.io.pipe.PipeListener;

public class ListenerStream extends InputStream {

	private final InputStream in;
	private final PipeListener listener;

	private int length, sofar = 0;
	private byte[] head, tail, single = new byte[1];
	private boolean endSent = false;
	
	public ListenerStream(int length, int head, int tail, PipeListener listener, InputStream in) {
		this.length = length;
		this.head = new byte[head];
		this.tail = new byte[tail];
		this.listener = listener;
		this.in = in;
	}
	
	@Override
	public int read() throws IOException {
		return read(single) < 0? -1 : single[0];
	}

	@Override
	public int read(byte[] b) throws IOException {
		return read(b, 0, b.length);
	}
	
	private void readFully(byte[] buf) throws IOException {
		int sofar = 0, tmp;
		if(buf.length == 0) return;
		while((tmp = in.read(buf, sofar, buf.length - sofar)) >= 0) {
			sofar += tmp;
			if(sofar >= buf.length)
				return;
		}
	}
	
	@Override
	public int read(byte[] b, int off, int len) throws IOException {
		try {
			len = Math.min(length, len);

			if(sofar == 0 && head != null) {
				readFully(head);
				head = null;
				if(listener != null)
					listener.onInitiate(length);
			}
			int ret = in.read(b, off, len);
			
			sofar += ret;

			if(listener != null)
				listener.onConnectionUpdate(sofar, length);

			if(sofar >= length && tail != null) {
				endSent = true;
				if(listener != null)
					listener.onComplete(length);
				readFully(tail);
				tail = null;
			}
			return ret;
		}
		catch(IOException e) {
			endSent = true;
			if(listener != null)
				listener.onError();
			throw e;
		}
	}
	
	public void close() throws IOException {
		if(!endSent) {
			endSent = true;
			if(listener != null)
				listener.onError();
		}
		in.close();
	}
	
}
